// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. Core Interrupt Controller
// -------------------------------------------------------------------------------------------------

module k0a_core_cic (
    input  wire         core_clk        ,
    input  wire         core_rstn       ,

    input  wire [15:0]  irq_lines       ,

    input  wire         csr2cic_gie     ,
    input  wire [15:0]  csr2cic_mie     ,
    input  wire [15:0]  csr2cic_mip     ,
    output wire [15:0]  cic2csr_irq     ,
    output reg  [4:0]   cic2csr_mcause  ,

    output reg          cic2idu_int_req ,
    input  wire         idu2cic_int_ack ,
    input  wire         idu2cic_int_mret
);

reg     status_irq;

wire cic_int_hit = cic2idu_int_req & idu2cic_int_ack;

wire [15:0] irq_src  = csr2cic_mip & csr2cic_mie;

assign cic2csr_irq = irq_lines;

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        status_irq <= 1'b0;
    else if(cic_int_hit)
        status_irq <= 1'b1;
    else if(idu2cic_int_mret)
        status_irq <= 1'b0;
end

always @(posedge core_clk)
begin
    if(csr2cic_gie) begin
        case(1'b1)
            irq_src[ 0] : cic2csr_mcause <= {1'b1, 4'h0};
            irq_src[ 1] : cic2csr_mcause <= {1'b1, 4'h1};
            irq_src[ 2] : cic2csr_mcause <= {1'b1, 4'h2};
            irq_src[ 3] : cic2csr_mcause <= {1'b1, 4'h3};
            irq_src[ 4] : cic2csr_mcause <= {1'b1, 4'h4};
            irq_src[ 5] : cic2csr_mcause <= {1'b1, 4'h5};
            irq_src[ 6] : cic2csr_mcause <= {1'b1, 4'h6};
            irq_src[ 7] : cic2csr_mcause <= {1'b1, 4'h7};
            irq_src[ 8] : cic2csr_mcause <= {1'b1, 4'h8};
            irq_src[ 9] : cic2csr_mcause <= {1'b1, 4'h9};
            irq_src[10] : cic2csr_mcause <= {1'b1, 4'ha};
            irq_src[11] : cic2csr_mcause <= {1'b1, 4'hb};
            irq_src[12] : cic2csr_mcause <= {1'b1, 4'hc};
            irq_src[13] : cic2csr_mcause <= {1'b1, 4'hd};
            irq_src[14] : cic2csr_mcause <= {1'b1, 4'he};
            irq_src[15] : cic2csr_mcause <= {1'b1, 4'hf};
            default     : cic2csr_mcause <= 5'd0;
        endcase
    end
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        cic2idu_int_req <= 1'b0;
    else if(cic_int_hit)
        cic2idu_int_req <= 1'b0;
    else if(~status_irq & (|irq_src))
        cic2idu_int_req <= 1'b1;
end

endmodule
